import React from 'react'
import _ from 'underscore'
import DefaultLoadingElement from 'lib/util/defaultLoadingElement.jsx'
import DefaultNoDataElement from 'lib/util/defaultNoDataElement.jsx'
import DefaultErrorElement from 'lib/util/defaultErrorElement.jsx'
import dispatcher from 'lib/dispatcher'
import cx from 'classnames';
import ReactTooltip from 'lib/components/tooltip.jsx';

export default class GridWidget extends React.Component{
  constructor(props){
    super(props);
    this.cellRenderContainer = props.container || this;
    this.state = {
      cols:_.map(props.cols,function(col){
        return _.defaults(col,{
          width:'auto',
          title:'',
          className:'',
          sortable:false,
          formatter:function(v){return v},
          render:function(cellData,rowData,rowIndex,colIndex){
            return cellData
          }
        })
      },this),
      currentSort: null
    };
    this.getOrder = this.props.store.getOrder
    this.fetch = this.props.store.fetch
    this.showMore = this.showMore.bind(this);
    this.getColumnStyle = this.getColumnStyle.bind(this);
  }
  componentWillReceiveProps(newProps){
    this.setState({
      cols:_.map(newProps.cols,function(col){
        return _.defaults(col,{
          width:'auto',
          title:'',
          className:'',
          sortable:false,
          formatter:function(v){return v},
          render:function(cellData,rowData,rowIndex,colIndex){
            return cellData
          }
        })
      },this)
    })
  }
  getColumnStyle(column) {
    if (column.width === 'auto') {
      return column.containerStyle;
    } else {
      return _.extend({width:column.width}, column.containerStyle);
    }
  }
  showMore(){
    var _this = this
    this.props.store.showMore().then(function(parsedData){
      if(parsedData){
        _this.props.store.data = _this.props.store.data.concat(parsedData.data)
        _this.props.store.hasMore = parsedData.hasMore
      }
      _this.forceUpdate()
    },function(){
      _this.forceUpdate()
    },function(){
      _this.forceUpdate()
    })
  }
  handleSort(key){
    let onSort = this.props.onSort;

    var sortScend = this.props.store.sortScend||1
    if(this.props.store.hasMore){
      this.getOrder.setNewOrder(key,sortScend*(-1))
      this.fetch()
    }else{
      sortScend = sortScend * (-1);

      if (_.isFunction(onSort)) {
        return onSort(key, sortScend);
      }

      this.props.store.data = _.sortBy(this.props.store.data,function(i){
        return i[key];
      },this);

      if(sortScend < 0){
        this.props.store.data.reverse();
      }

      this.props.store.sortKey = key;
      this.props.store.sortScend = sortScend
      this.forceUpdate()
    }

  }
  renderNoData(){
    return (
      <tr>
        <td colSpan={this.state.cols.length}>
          {this.props.nodataElement}
        </td>
      </tr>
    )
  }
  renderCol(col,colIndex){
    if(col.sortable){
      return (
        <th
          key={colIndex}
          className="sortedth"
          onClick={this.handleSort.bind(this,col.key)}
          style={this.getColumnStyle(col)}>
          <span className="sortedtext" {...col.tooltip}>
            {col.title}
          </span>
          <span className={cx({
              'sorted-arrow':true,
              'desc':this.props.store.sortKey===col.key&&this.props.store.sortScend===-1,
              'asc':this.props.store.sortKey===col.key&&this.props.store.sortScend===1
            })+' '+col.className}/>
        </th>
      )
    }else{
      return (
        <th key={colIndex} className={col.className} style={this.getColumnStyle(col)}>
          {this.props.contentRender(col, true, () => col.title, { columnIndex: colIndex })}
        </th>
      )
    }
  }
  renderCell(rowData, col, rowIndex, colIndex) {
    let contentCallback = () => {
      let contentText = (!_.isUndefined(rowData[col.key]) || !_.isNull(rowData[col.key]))
        ? col['formatter'].call(rowData, rowData[col.key])
        : null;

      return col.render.call(this.cellRenderContainer, contentText, rowData, rowIndex, colIndex);
    };

    return (
      <td key={colIndex} className={col.className} style={this.getColumnStyle(col)}>
        {
          this.props.contentRender(col, false, contentCallback, {
            rowData,
            rowIndex,
            columnIndex: colIndex
          })
        }
      </td>
    );
  }
  renderRow(rowData,rowIndex){
    return (
      <tr key={rowIndex} className={this.props.rowClassName} style={this.props.rowStyle}>
      {
        this.state.cols.map(function(col,colIndex){
          return this.renderCell(rowData,col,rowIndex,colIndex)
        },this)
      }
      </tr>
    )
  }
  renderLoading(){
    return this.props.store.loading?(
      <tr>
        <td colSpan={this.state.cols.length}>
          {this.props.loadingElement}
        </td>
      </tr>
    ):null
  }
  renderBody(){
    if(this.props.store.loading){
      return null
    }else{
      if(this.props.store.error){
        return (
          <tr>
            <td colSpan={this.state.cols.length}>
              {this.props.errorElement}
            </td>
          </tr>
        )
      }else{
        if(!this.props.store.data.length){
          return this.renderNoData()
        }else{
          return this.props.store.data.map(this.renderRow,this)
        }
      }
    }
  }
  render(){
    return (
      <div className={ this.props.className }>
        <table className={cx({
          "table":true,
          "table-striped":this.props.oddColor
        })+' '+this.props.extraClassName} style={this.props.tableStyle}>
          <colgroup>
            {
              this.state.cols.map((col) => {
                return (
                  <col key={col.key} style={this.getColumnStyle(col)}></col>
                )
              }, this)
            }
          </colgroup>
          {
            this.props.showCols ? (
              <thead>
                <tr key="thead_tr" className={this.props.rowClassName} style={this.props.rowStyle}>
                {
                  this.state.cols.map(this.renderCol,this)
                }
                </tr>
              </thead>
            ) : null
          }
          <tbody>
            {
              this.renderBody()
            }
            {
              this.renderLoading()
            }
          </tbody>
        </table>
        {
          this.props.store.hasMore?(
            <div className="show-more">
              <a href="javascript:;" onClick={this.showMore}>
                显示更多
              </a>
            </div>
          ):null
        }
      </div>
    )
  }
}
GridWidget.defaultProps = {
  className: null,
  loadingElement:<DefaultLoadingElement />,
  errorElement:<DefaultErrorElement />,
  nodataElement:<DefaultNoDataElement />,
  extraClassName:'',
  rowStyle:{},
  rowClassName:'',
  tableStyle:{},
  oddColor:true,
  showCols:true,
  cols:[],
  onSort: null,
  contentRender:(column, isHeader, callback, options) => callback(),
  store:{
    loading:false,
    hasMore:true,
    error:null,
    data:[]
  }
}
